﻿using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Windows.Forms;

namespace Silent.HotKeys
{
    public static class HotkeyManager
    {
        private static readonly Dictionary<int, InnerWindow> m_windows = new Dictionary<int, InnerWindow>();
        private static int m_currentId;

        public static void Dispose()
        {
            foreach (var item in m_windows)
            {
                NativeMethods.UnregisterHotKey(item.Value.Handle, item.Key);
                item.Value.Dispose();
            }
        }
        public static bool Register(ModifierKeys modifier, Keys key, EventHandler<KeyPressedEventArgs> action)
        {
            var window = new InnerWindow();
            window.KeyPressed += action;
            m_currentId++;

            if (NativeMethods.RegisterHotKey(window.Handle, m_currentId, (uint)modifier, (uint)key))
            {
                m_windows.Add(m_currentId, window);
                return true;
            }

            return false;
        }

        private sealed class InnerWindow : NativeWindow, IDisposable
        {
            private const int WM_HOTKEY = 0x0312;

            public InnerWindow()
            {
                CreateHandle(new CreateParams());
            }

            public event EventHandler<KeyPressedEventArgs> KeyPressed;

            protected override void WndProc(ref Message m)
            {
                base.WndProc(ref m);

                if (m.Msg == WM_HOTKEY)
                {
                    var key = (Keys) (((int) m.LParam >> 16) & 0xFFFF);
                    var modifier = (ModifierKeys) ((int) m.LParam & 0xFFFF);

                    // invoke the event to notify the parent.
                    if (KeyPressed != null)
                    {
                        KeyPressed(this, new KeyPressedEventArgs(modifier, key));
                    }
                }
            }

            public void Dispose()
            {
                DestroyHandle();
            }
        }
    }

    public static class NativeMethods
    {
        [DllImport("user32.dll")]
        public static extern bool RegisterHotKey(IntPtr hWnd, int id, uint fsModifiers, uint vk);
        [DllImport("user32.dll")]
        public static extern bool UnregisterHotKey(IntPtr hWnd, int id);
    }
}